package com.lxl.priv.csv;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import com.lxl.priv.bak.DemoBO;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVPrinter;
import org.apache.commons.csv.CSVRecord;
import org.springframework.util.FileCopyUtils;

import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

public class MergeCsv {

    public static void main(String[] args) throws IOException {
        String outputFile = "D:\\tmp\\单主键无冗余.csv";
        // 一、单主键无冗余 succeed
        // 二、单主键有冗余 succeed
        // 三、双主键无冗余 succeed
        // 四、双主键有冗余 succeed
        List<DemoBO> fileDtl = new ArrayList<>();
        fileDtl.add(new DemoBO(1, 0, "D:\\tmp\\1.csv", "label1"));
        fileDtl.add(new DemoBO(1, 0, "D:\\tmp\\2.csv", "label2"));
        fileDtl.add(new DemoBO(1, 0, "D:\\tmp\\3.csv", "label3"));
        // 判断是第几个文件
        for (int i = 1; i <= fileDtl.size(); i++) {
            mergeCsvFiles(fileDtl.get(i - 1), outputFile, i);
        }
    }

    public static void mergeCsvFiles(DemoBO demoBO, String outputFile, int fileIndex) throws IOException {
        CSVPrinter csvPrinter = new CSVPrinter(new FileWriter(outputFile, true), CSVFormat.DEFAULT);
        CSVParser csvParser = new CSVParser(new FileReader(demoBO.getFilePath()), CSVFormat.DEFAULT);
        // 是否是银联数据
        boolean isYl = false;
        // 前一个文件头个数
        int size = 0;
        // 主键个数
        int encHeadLen = demoBO.getEncHeadLen();
        // 冗余字段个数
        int extraLen = demoBO.getExtraLen();

        Iterator<CSVRecord> iterator = csvParser.iterator();
        // 原始文件数据
        List<CSVRecord> csvRecords = new ArrayList<>();
        // 备份文件数据
        List<CSVRecord> tmpCsvRecords = new ArrayList<>();
        // 新文件数据
        List<CSVRecord> newCsvRecords = new ArrayList<>();

        // 判断是否是第一个文件
        if (1 == fileIndex) {
            while (iterator.hasNext()) {
                CSVRecord record = iterator.next();
                if (1 == record.getRecordNumber()) {
                    String[] values = record.values();
                    // 生成文件头
                    String[] arr = isYl ? new String[values.length] : new String[values.length + 1];
                    for (int i = 0; i < values.length; i++) {
                        arr[i] = values[i];
                        if (!isYl) {
                            arr[i + 1] = "label";
                        }
                        boolean flag = checkData(arr);
                        if (i == values.length - 1 && flag) {
                            csvPrinter.printRecord(arr);
                            csvPrinter.flush();
                        }
                    }
                    continue;
                }
                csvRecords.add(record);
                if (csvRecords.size() > 5000) {
                    mergeCsv(demoBO, csvRecords, isYl, csvPrinter);
                    csvPrinter.flush();
                    csvRecords.clear();
                }
            }
            mergeCsv(demoBO, csvRecords, isYl, csvPrinter);
            csvPrinter.flush();
            csvRecords.clear();
            csvPrinter.close();
        }

        // 如果多个文件，进行合并操作
        if (1 != fileIndex) {
            // 获取待合并的文件头
            String[] needHead = iterator.next().values();
            // 创建备份文件 - 存储修改后的文件
            String tmpFilePath = outputFile + ".tmp";
            // 写入备份文件
            CSVPrinter tmpCsvPrinter = new CSVPrinter(new FileWriter(tmpFilePath), CSVFormat.DEFAULT);
            // 读取上一个组合文件
            CSVParser beforeCsvParser = new CSVParser(new FileReader(outputFile), CSVFormat.DEFAULT);
            // 先把文件格式生成好
            Iterator<CSVRecord> beforeCsvRecord = beforeCsvParser.iterator();
            while (beforeCsvRecord.hasNext()) {
                CSVRecord record = beforeCsvRecord.next();
                if (1 == record.getRecordNumber()) {
                    String[] values = record.values();
                    //String[] newArr = new String[values.length + extraLen];
                    List<String> oriHead = Arrays.asList(values);
                    List<String> head = new ArrayList<>();
                    head.addAll(oriHead);
                    for (int i = 0; i < extraLen; i++) {
                        head.add(oriHead.size() - 1, needHead[i + encHeadLen]);
                    }
                    tmpCsvPrinter.printRecord(head);
                    tmpCsvPrinter.flush();
                    size = head.size();
                    continue;
                }
                tmpCsvRecords.add(record);
                if (tmpCsvRecords.size() > 5000) {
                    mergeBeforeCsv(demoBO, tmpCsvRecords, isYl, tmpCsvPrinter, extraLen, encHeadLen);
                    tmpCsvPrinter.flush();
                    tmpCsvRecords.clear();
                }
            }
            mergeBeforeCsv(demoBO, tmpCsvRecords, isYl, tmpCsvPrinter, extraLen, encHeadLen);
            tmpCsvRecords.clear();
            tmpCsvPrinter.flush();
            tmpCsvPrinter.close();
            beforeCsvParser.close();
            FileCopyUtils.copy(new File(tmpFilePath), new File(outputFile));
            // 删除源临时文件
            FileUtil.del(tmpFilePath);
            // 合并新的文件
            CSVPrinter newCsvPrinter = new CSVPrinter(new FileWriter(outputFile, true), CSVFormat.DEFAULT);
            while (iterator.hasNext()) {
                CSVRecord record = iterator.next();
                if (1 == record.getRecordNumber()) {
                    continue;
                }
                newCsvRecords.add(record);
                if (tmpCsvRecords.size() > 5000) {
                    mergeNewCsv(demoBO, newCsvRecords, isYl, newCsvPrinter, size, extraLen, encHeadLen);
                    newCsvPrinter.flush();
                    newCsvRecords.clear();
                }
            }
            mergeNewCsv(demoBO, newCsvRecords, isYl, newCsvPrinter, size, extraLen, encHeadLen);
            newCsvPrinter.flush();
            newCsvRecords.clear();
            csvParser.close();
            newCsvPrinter.close();

        }
    }

    private static void mergeNewCsv(DemoBO demoBO, List<CSVRecord> newCsvRecords, boolean isYl, CSVPrinter newCsvPrinter, int size, int extraLen, int enHeadLen) {
        newCsvRecords.forEach(records -> {
            String[] values = records.values();
            // 生成文件头
            String[] arr = new String[size];
            for (int i = 0; i < enHeadLen; i++) {
                arr[i] = values[i];
            }
            for (int i = enHeadLen; i <= size - 1 - extraLen; i++) {
                arr[i] = "";
            }
            for (int len = extraLen; len > 0; len--) {
                arr[arr.length - len - 1] = values[values.length - extraLen];
            }
            arr[arr.length - 1] = demoBO.getLabel();
            try {
                newCsvPrinter.printRecord(arr);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        });
    }

    private static void mergeBeforeCsv(DemoBO demoBO, List<CSVRecord> tmpCsvRecords, boolean isYl, CSVPrinter tmpCsvPrinter, int extraLen, int encHeadLen) {
        tmpCsvRecords.forEach(records -> {
            String[] values = records.values();
            // 生成文件头
            String[] arr = isYl ? new String[values.length] : new String[values.length + 1];
            List<String> oriCont = Arrays.asList(values);
            List<String> cont = new ArrayList<>();
            cont.addAll(oriCont);
            for (int i = 0; i < extraLen; i++) {
                cont.add(oriCont.size() - 1, "");
            }
            try {
                tmpCsvPrinter.printRecord(cont);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        });
    }


    private static void mergeCsv(DemoBO demoBO, List<CSVRecord> csvRecords, boolean isYl, CSVPrinter csvPrinter) {
        csvRecords.forEach(records -> {
            String[] values = records.values();
            // 生成文件头
            String[] arr = isYl ? new String[values.length] : new String[values.length + 1];
            for (int i = 0; i < values.length; i++) {
                arr[i] = values[i];
                if (!isYl) {
                    arr[i + 1] = demoBO.getLabel();
                }
            }
            try {
                csvPrinter.printRecord(arr);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        });
    }

    private static boolean checkData(String[] arr) {
        for (String str : arr) {
            if (StrUtil.isEmpty(str)) {
                return false;
            }
        }
        return true;
    }

}
